﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;

namespace Messaging2
{
    internal sealed class  Listener : IDisposable, IListener
    {
        public event EventHandler MessageRecieved,  MessageResend;

        private readonly ConcurrentBag<string> _cacheTopics, _listenTopics = new ConcurrentBag<string>();
        private readonly Connection _conn;
        private delegate void del(Connection conn);
        private del _ld;

        //construct
        public Listener(Connection conn, ConcurrentBag<string> cacheTopics)
        {
            _cacheTopics = cacheTopics;
            _conn = conn;

            _ld = new del(this.Listen);
            _ld.BeginInvoke(_conn, null, null);
        }

        //public
        public void Listen(string topic)
        {
            _listenTopics.Add(topic);//can have same topic more than once
        }

        public void Stop(string topic)
        {
            _listenTopics.TryTake(out topic);
        }

        public void Dispose()
        {
            _ld = null;
            if (_conn != null) _conn.Dispose();
        }

        //private
        private void Listen(Connection conn)
        {
            var handler = MessageRecieved;
            while (true)
            {
                try
                {
                    var data = _conn.Client.Receive(ref _conn.Endpoint);
                    var message = new Message(Encoding.Unicode.GetString(data));

                    if (_cacheTopics.Contains(message.Topic) && message.RequestResendCache)
                    {
                        var handlerResend = MessageResend;
                        handlerResend(this, new MessageEventArgs(message));
                    }
                    else if (handler != null && _listenTopics.Contains(message.Topic) && !message.RequestResendCache)
                    {
                        handler(this, new MessageEventArgs(message));
                    }
                }
                catch (Exception e)
                {
                    if (_listenTopics.Contains("Error"))
                        handler(this, new MessageEventArgs(new Message(e)));
                }
            }
        }
    }
}
